/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

import javax.swing.JOptionPane;

//import java.io.*;
//import java.util.*;

/*This is class file for the Instruction Set Simulator for SIMD approach.
 * This class defines main instructions each CFU can perform*/

/*The following instructions are used in this architecture. There is a method
 * for each instruction which takes some arguments and returns output; These
 * will be mostly registers.
 *
 * 1- ADD - Addition of two 16 bits data
 * 2- MAC - Multiply and accumulation (MAC) in single cycle; We have only used
 * 			MAC unit instead of multiply unit because in terms of area it does not make
 * 			much more difference.
 * 3- SLL - Shift Left Logical
 * 4- SRL - Shift Right Logical
 * 5- NOP - No Operation
 * 6- ADM - Addition and multiplication (ADM) in single cycle, not that the order
 * 			of operation is reverse than MAC instruction.
 * */

public class Cfu_NOC {

	/*
	 * Registers; There are four 16 bits registers in each CFU Two register to
	 * hold the input data to process Two registers to hold the output data
	 * because size of the output data may be larger than the input data
	 */

	// Global Variables
	public static int NumberOfRegisters;//Default should be 5.
	
	public long[] register_array = new long[NumberOfRegisters];

	public int  in_reg1_index, in_reg2_index, in_reg3_index,
			in_reg4_index, out_reg_index, shift_offset;

	public int router_reg_index_hex;
	
	public boolean router_enable;
	// Usage Counters
	public static int Register_Accesses, CFUs_Reconfigurations, NOP_Operations,
			Add_Operations, Shift_Left_Operations, Shift_Right_Operations,
			MAC_Operations, ADM_Operations, Sub_Operations,MSUB_Operations, MUL_Operations
			;

	// Defining Instructions

	public enum Instruction_List{ NOP , ADD , SUB, SHIFT_LEFT , SHIFT_RIGHT ,
			MAC ,MSUB, ADM , SBM, MACSHIR , MACSHIL, MUL }
			// ROUTER = 8

	Instruction_List instruction;
	
	public void Cfu_initialize(Instruction_List instruction, 
			int in_reg1, int in_reg2,
			int in_reg3, int in_reg4,
			int out_reg, //output register index
			int offset, //shift offset input
			int router_reg_index //router register index
			)
	{

		this.instruction = instruction;
		in_reg1_index = in_reg1;
		in_reg2_index = in_reg2;
		in_reg3_index = in_reg3;
		in_reg4_index = in_reg4;
		out_reg_index = out_reg;
		shift_offset = offset;
		router_reg_index_hex = router_reg_index;
		// register_array[0]=7;
		// register_array[1]=9;
		// register_array[2]=11;

		// Increase the usage counter for CFUs
		CFUs_Reconfigurations++;
	}

	public void update_register(int register_index, long new_value) {
		// Increase the usage counter for registers
		Register_Accesses++;
		// put one counter here to calculate number of register accesses
		register_array[register_index] = new_value;
	}

	public void clear_register(int register_index)

	{
		register_array[register_index] = 0;
	}

	public void copy_register(int source_register_index,
			int destination_registor_index)

	{

	}
	public void nop()
	{
		NOP_Operations++;
	}

	// Method of Addition operation
	public void add() {

		register_array[out_reg_index] = register_array[in_reg1_index]
				+ register_array[in_reg2_index];

		if (ISS_SIMD_Form_Main.rounding_enable)
		register_array[out_reg_index] = Bitwidth_Manipulation.Round_Result(register_array[out_reg_index]);
		Register_Accesses++;
		// Increase the usage counter for Addition operations
		Add_Operations++;
			

	}

	// Method of Subtraction operation
	public void sub() {

		register_array[out_reg_index] = register_array[in_reg1_index]
				- register_array[in_reg2_index];
		
		if (ISS_SIMD_Form_Main.rounding_enable)		
		register_array[out_reg_index] = Bitwidth_Manipulation.Round_Result(register_array[out_reg_index]);
		Register_Accesses++;
		// Increase the usage counter for Addition operations
		Sub_Operations++;
		

	}
	


	// Method of MAC (Multiply Accumulate) operation
	public void mac() {

		register_array[out_reg_index] = (register_array[in_reg1_index] * register_array[in_reg2_index])
				+ register_array[in_reg3_index];

		if (ISS_SIMD_Form_Main.rounding_enable)		
		register_array[out_reg_index] = Bitwidth_Manipulation.Round_Result(register_array[out_reg_index]);
		Register_Accesses++;
		//register_array[in_reg3_index] = (register_array[in_reg1_index] * register_array[in_reg2_index]);
		// Increase the usage counter for MAC operations
		MAC_Operations++;
		
		/*
		 * We only need to write output when we have the final output. So, we have defined
		 * a flag which would indicate whether the result should be written to output file or not.
		 * The flag will be set by mapping class file of the particular application.
		 */
		
//		if (Ram.write_output_flag)
//		Ram.Write_Output(register_array[out_reg_index]);

	}
	
	public void mul()
	{
		register_array[out_reg_index] = register_array[in_reg1_index] * register_array[in_reg2_index];

		if (ISS_SIMD_Form_Main.rounding_enable)		
		register_array[out_reg_index] = Bitwidth_Manipulation.Round_Result(register_array[out_reg_index]);
		// Increase the usage counter for MAC operations
		MUL_Operations++;
		
	}


	/*
	 * Input arguments to this class will be in the following order 0-
	 * Instruction 1- 1st input register index 2- 2nd input register index; pass
	 * null if not required 3- 3rd input register index; pass null if not
	 * required 4- Output register index 5- Shift offset
	 */

	public  void start_CFU() {

		if(router_reg_index_hex == 0xffff)
		{
			router_enable = false;
		}
		else
			router_enable = true;
		
		/* Instruction Decoding Logic for CFU */

		
		switch (instruction) {

		// This is NOP operation
		case NOP:
			
			//System.out.println("You have chosen NOP instruction and CFU will be idle");
			nop();
	
		case ADD:

			/*
			 * Argument order - input register 1 index, input register 2 index,
			 * output register index
			 */
			add();
			//System.out.println("You have chosen ADD instruction");
			if (router_enable)
				router();
			
			break;
			
		case SUB:

			/*
			 * Argument order - input register 1 index, input register 2 index,
			 * output register index
			 */
			sub();
			//System.out.println("You have chosen SUB instruction");
			if (router_enable)
				router();
			
			break;
			
		// This is Shift Left logical operation
		case SHIFT_LEFT:
			sll();
			if (router_enable)
				router();
			
			break;

		// This is Shift right logical operation
		case SHIFT_RIGHT:
			srl();
			if (router_enable)
				router();

			break;

		// This is MAC operation
		case MAC:
			mac();
			if (router_enable)
				router();

			break;

		case MSUB:
			msub();
			if (router_enable)
				router();

			break;
			
		// This is ADM (Addition and multiplication) operation
		case ADM:
			adm();
			if (router_enable)
				router();

			break;

		/*
		 * This in newly added instruction which performs Right Shift and MAC
		 * operation in one cycle
		 */

		case MACSHIR:
			// macshir(in_reg1_index, in_reg2_index, in_reg3_index,
			// in_reg4_index, shift_offset, out_reg_index);
			macshir();
			if (router_enable)
				router();

			break;

		/*
		 * This in newly added instruction which performs Right Shift and MAC
		 * operation in one cycle
		 */

		case MACSHIL:
			macshil(in_reg1_index, in_reg2_index, in_reg3_index, in_reg4_index,
					shift_offset, out_reg_index);
			if (router_enable)
				router();
			
			break;
			
		case MUL:
			
			mul();
			if (router_enable)
				router();
			break;
		// case ROUTER:
		// router();
		// break;
		default:
			JOptionPane.showMessageDialog(null,
					"The operation to CFU is not valid");

		}
		// JOptionPane.showMessageDialog(null, "The final answer from CFU is "+
		// register_array[out_reg_index] );
		// System.out.println("Your final answer from CFU is "+
		// register_array[out_reg_index]);
		//return (register_array[out_reg_index]);
	}
	
	public static void Reset_Statistical_Counters()
	{
		Register_Accesses = 0;CFUs_Reconfigurations =0; NOP_Operations =0;
		Add_Operations=0; Shift_Left_Operations=0; Shift_Right_Operations=0;
		MAC_Operations=0; ADM_Operations=0; Sub_Operations =0; 
		MSUB_Operations=0; MUL_Operations=0;
		
	}
}
